| <?php |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| abstract class Smarty_Internal_TemplateCompilerBase |
| { |
| |
| |
| |
| |
| |
| |
| public $suppressMergedTemplates = false; |
| |
| |
| |
| |
| |
| |
| public static $_tag_objects = array(); |
| |
| |
| |
| |
| |
| |
| public $_tag_stack = array(); |
| |
| |
| |
| |
| |
| |
| public $template = null; |
| |
| |
| |
| |
| |
| |
| public $merged_templates = array(); |
| |
| |
| |
| |
| |
| |
| public $sources = array(); |
| |
| |
| |
| |
| |
| |
| public $inheritance = false; |
| |
| |
| |
| |
| |
| |
| public $inheritance_child = false; |
| |
| |
| |
| |
| |
| |
| public $extends_uid = array(); |
| |
| |
| |
| |
| |
| |
| public $trace_line_offset = 0; |
| |
| |
| |
| |
| |
| |
| public $trace_uid = ''; |
| |
| |
| |
| |
| |
| |
| public $trace_filepath = ''; |
| |
| |
| |
| |
| |
| public $trace_stack = array(); |
| |
| |
| |
| |
| |
| |
| public $default_handler_plugins = array(); |
| |
| |
| |
| |
| |
| |
| public $default_modifier_list = null; |
| |
| |
| |
| |
| |
| public $suppressHeader = false; |
| |
| |
| |
| |
| |
| public $suppressTemplatePropertyHeader = false; |
| |
| |
| |
| |
| |
| public $suppressFilter = false; |
| |
| |
| |
| |
| |
| public $write_compiled_code = true; |
| |
| |
| |
| |
| |
| public $compiles_template_function = false; |
| |
| |
| |
| |
| |
| public $called_functions = array(); |
| |
| |
| |
| |
| |
| public $modifier_plugins = array(); |
| |
| |
| |
| |
| |
| public $known_modifier_type = array(); |
| |
| |
| |
| |
| public $has_code = false; |
| |
| |
| |
| |
| |
| |
| |
| abstract protected function doCompile($_content); |
| |
| |
| |
| |
| |
| |
| |
| public function compileTemplate(Smarty_Internal_Template $template) { |
| |
| $this->template = $template; |
| $save_source = $this->template->source; |
| |
| $template_header = ''; |
| if (!$this->suppressHeader) { |
| $template_header .= "<?php /* Brainy version " . Smarty::SMARTY_VERSION . ", created on " . strftime("%Y-%m-%d %H:%M:%S") . "\n"; |
| $template_header .= " compiled from \"" . $this->template->source->filepath . "\" */\n"; |
| } |
| |
| if (empty($this->template->source->components)) { |
| $this->sources = array($template->source); |
| } else { |
| |
| $this->sources = array_reverse($template->source->components); |
| } |
| $loop = 0; |
| |
| while ($this->template->source = array_shift($this->sources)) { |
| $this->smarty->_current_file = $this->template->source->filepath; |
| $no_sources = count($this->sources); |
| if ($loop || $no_sources) { |
| $this->template->properties['file_dependency'][$this->template->source->uid] = array($this->template->source->filepath, $this->template->source->timestamp, $this->template->source->type); |
| } |
| $loop++; |
| $this->inheritance_child = (bool) $no_sources; |
| do { |
| $_compiled_code = ''; |
| |
| $this->abort_and_recompile = false; |
| |
| $_content = $this->template->source->content; |
| if ($_content != '') { |
| |
| if ((isset($this->smarty->autoload_filters['pre']) || isset($this->smarty->registered_filters['pre'])) && !$this->suppressFilter) { |
| $_content = Smarty_Internal_Filter_Handler::runFilter('pre', $_content, $template); |
| } |
| |
| $_compiled_code = $this->doCompile($_content); |
| } |
| } while ($this->abort_and_recompile); |
| } |
| |
| |
| $this->template->source = $save_source; |
| unset($save_source); |
| $this->smarty->_current_file = $this->template->source->filepath; |
| |
| unset($this->parser->root_buffer, $this->parser->current_buffer, $this->parser, $this->lex, $this->template); |
| self::$_tag_objects = array(); |
| |
| $merged_code = ''; |
| if (!$this->suppressMergedTemplates && !empty($this->merged_templates)) { |
| foreach ($this->merged_templates as $code) { |
| $merged_code .= $code; |
| } |
| } |
| |
| if ((isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) && !$this->suppressFilter && $_compiled_code !== '') { |
| $_compiled_code = Smarty_Internal_Filter_Handler::runFilter('post', $_compiled_code, $template); |
| } |
| if ($this->suppressTemplatePropertyHeader) { |
| $code = $_compiled_code . $merged_code; |
| } else { |
| $code = $template_header . $template->createTemplateCodeFrame($_compiled_code) . $merged_code; |
| } |
| |
| unset ($template->source->content); |
| |
| return $code; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function compileTag($tag, $args, $parameter = array(), $param2 = null, $param3 = null) { |
| |
| |
| $this->has_code = true; |
| $this->has_output = false; |
| |
| if (isset($this->smarty->get_used_tags) && $this->smarty->get_used_tags) { |
| $this->template->used_tags[] = array($tag, $args); |
| } |
| |
| $_output = $this->callTagCompiler($tag, $args, $parameter, $param2, $param3); |
| |
| if ($_output === false && isset($this->smarty->template_functions[$tag])) { |
| |
| $args['_attr']['name'] = "'" . $tag . "'"; |
| $_output = $this->callTagCompiler('call', $args, $parameter); |
| } |
| |
| if ($_output !== false) { |
| if ($_output !== true) { |
| |
| if ($this->has_code) { |
| |
| if ($this->has_output) { |
| $_output .= "\n"; |
| } |
| |
| return $_output; |
| } |
| } |
| |
| return null; |
| } |
| |
| if (isset($args['_attr'])) { |
| foreach ($args['_attr'] as $key => $attribute) { |
| if (is_array($attribute)) { |
| $args = array_merge($args, $attribute); |
| } |
| } |
| } |
| |
| if (strlen($tag) < 6 || substr($tag, -5) !== 'close') { |
| |
| if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag])) { |
| $new_args = array(); |
| foreach ($args as $key => $mixed) { |
| if (is_array($mixed)) { |
| $new_args = array_merge($new_args, $mixed); |
| } else { |
| $new_args[$key] = $mixed; |
| } |
| } |
| $function = $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0]; |
| if (!is_array($function)) { |
| return $function($new_args, $this); |
| } elseif (is_object($function[0])) { |
| return $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0][0]->$function[1]($new_args, $this); |
| } else { |
| return call_user_func_array($function, array($new_args, $this)); |
| } |
| } |
| if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_FUNCTION][$tag])) { |
| return $this->callTagCompiler('private_registered_' . Smarty::PLUGIN_FUNCTION, $args, $parameter, $tag); |
| } |
| if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$tag])) { |
| return $this->callTagCompiler('private_registered_' . Smarty::PLUGIN_BLOCK, $args, $parameter, $tag); |
| } |
| |
| |
| foreach ($this->smarty->plugin_search_order as $plugin_type) { |
| if ($plugin_type == Smarty::PLUGIN_COMPILER && |
| $this->smarty->loadPlugin('smarty_compiler_' . $tag, true) && |
| (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))) { |
| |
| $plugin = 'smarty_compiler_' . $tag; |
| if (is_callable($plugin)) { |
| |
| $new_args = array(); |
| foreach ($args as $key => $mixed) { |
| if (is_array($mixed)) { |
| $new_args = array_merge($new_args, $mixed); |
| } else { |
| $new_args[$key] = $mixed; |
| } |
| } |
| |
| return $plugin($new_args, $this->smarty); |
| } |
| if (class_exists($plugin, false)) { |
| $plugin_object = new $plugin; |
| if (method_exists($plugin_object, 'compile')) { |
| return $plugin_object->compile($args, $this); |
| } |
| } |
| throw new SmartyException("Plugin \"{$tag}\" not callable"); |
| |
| } |
| |
| $function = $this->getPlugin($tag, $plugin_type); |
| if ($function && (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))) { |
| return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $parameter, $tag, $function); |
| } |
| } |
| if (is_callable($this->smarty->default_plugin_handler_func)) { |
| $found = false; |
| |
| foreach ($this->smarty->plugin_search_order as $plugin_type) { |
| if (isset($this->default_handler_plugins[$plugin_type][$tag]) || |
| $this->getPluginFromDefaultHandler($tag, $plugin_type)) { |
| $found = true; |
| break; |
| } |
| } |
| if ($found) { |
| |
| if ($plugin_type == Smarty::PLUGIN_COMPILER) { |
| $new_args = array(); |
| foreach ($args as $mixed) { |
| $new_args = array_merge($new_args, $mixed); |
| } |
| $function = $this->default_handler_plugins[$plugin_type][$tag][0]; |
| if (!is_array($function)) { |
| return $function($new_args, $this); |
| } elseif (is_object($function[0])) { |
| return $this->default_handler_plugins[$plugin_type][$tag][0][0]->$function[1]($new_args, $this); |
| } else { |
| return call_user_func_array($function, array($new_args, $this)); |
| } |
| } else { |
| return $this->callTagCompiler('private_registered_' . $plugin_type, $args, $parameter, $tag); |
| } |
| } |
| } |
| $this->trigger_template_error("unknown compiler tag \"" . $tag . "\"", $this->lex->taglineno); |
| |
| } |
| |
| |
| $base_tag = substr($tag, 0, -5); |
| |
| if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag]) || isset($this->default_handler_plugins[Smarty::PLUGIN_BLOCK][$base_tag])) { |
| return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag); |
| } |
| |
| if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) { |
| return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function); |
| } |
| |
| if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag])) { |
| |
| $args = array(); |
| $function = $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0]; |
| if (!is_array($function)) { |
| return $function($args, $this); |
| } elseif (is_object($function[0])) { |
| return $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0][0]->$function[1]($args, $this); |
| } else { |
| return call_user_func_array($function, array($args, $this)); |
| } |
| } |
| if ($this->smarty->loadPlugin('smarty_compiler_' . $tag, true)) { |
| $plugin = 'smarty_compiler_' . $tag; |
| if (is_callable($plugin)) { |
| return $plugin($args, $this->smarty); |
| } |
| if (class_exists($plugin, false)) { |
| $plugin_object = new $plugin; |
| if (method_exists($plugin_object, 'compile')) { |
| return $plugin_object->compile($args, $this); |
| } |
| } |
| throw new SmartyException("Plugin \"{$tag}\" not callable"); |
| } |
| $this->trigger_template_error("unknown tag \"" . $tag . "\"", $this->lex->taglineno); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null) { |
| |
| if (isset(self::$_tag_objects[$tag])) { |
| |
| return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3); |
| } |
| |
| $class_name = 'Smarty_Internal_Compile_' . $tag; |
| |
| if ($this->smarty->loadPlugin($class_name, true)) { |
| |
| if (!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this)) { |
| |
| self::$_tag_objects[$tag] = new $class_name; |
| self::$_tag_objects[$tag]->template = $this->template; |
| |
| return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3); |
| } |
| } |
| |
| return false; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| public function getPlugin($plugin_name, $plugin_type) { |
| $function = null; |
| if (isset($this->template->required_plugins['compiled'][$plugin_name][$plugin_type])) { |
| $function = $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function']; |
| } |
| if (isset($function)) { |
| if ($plugin_type == 'modifier') { |
| $this->modifier_plugins[$plugin_name] = true; |
| } |
| |
| return $function; |
| } |
| |
| $function = 'smarty_' . $plugin_type . '_' . $plugin_name; |
| $file = $this->smarty->loadPlugin($function, false); |
| if ($file === true) { |
| return $function; |
| } |
| |
| if (is_string($file)) { |
| $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['file'] = $file; |
| $this->template->required_plugins['compiled'][$plugin_name][$plugin_type]['function'] = $function; |
| if ($plugin_type == 'modifier') { |
| $this->modifier_plugins[$plugin_name] = true; |
| } |
| |
| return $function; |
| } |
| if (is_callable($function)) { |
| |
| return $function; |
| } |
| |
| return false; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| public function getPluginFromDefaultHandler($tag, $plugin_type) { |
| $callback = null; |
| $script = null; |
| $cacheable = true; |
| $result = call_user_func_array( |
| $this->smarty->default_plugin_handler_func, array($tag, $plugin_type, $this->template, &$callback, &$script, &$cacheable) |
| ); |
| if ($result) { |
| if ($script !== null) { |
| if (is_file($script)) { |
| $this->template->required_plugins['compiled'][$tag][$plugin_type]['file'] = $script; |
| $this->template->required_plugins['compiled'][$tag][$plugin_type]['function'] = $callback; |
| include_once $script; |
| } else { |
| $this->trigger_template_error("Default plugin handler: Returned script file \"{$script}\" for \"{$tag}\" not found"); |
| } |
| } |
| if (!is_string($callback) && !(is_array($callback) && is_string($callback[0]) && is_string($callback[1]))) { |
| $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" must be a static function name or array of class and function name"); |
| } |
| if (is_callable($callback)) { |
| $this->default_handler_plugins[$plugin_type][$tag] = array($callback, true, array()); |
| |
| return true; |
| } else { |
| $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" not callable"); |
| } |
| } |
| |
| return false; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function pushTrace($file, $uid, $line, $debug = true) { |
| array_push($this->trace_stack, array($this->smarty->_current_file, $this->trace_filepath, $this->trace_uid, $this->trace_line_offset)); |
| $this->trace_filepath = $this->smarty->_current_file = $file; |
| $this->trace_uid = $uid; |
| $this->trace_line_offset = $line; |
| } |
| |
| |
| |
| |
| |
| public function popTrace() { |
| $r = array_pop($this->trace_stack); |
| $this->smarty->_current_file = $r[0]; |
| $this->trace_filepath = $r[1]; |
| $this->trace_uid = $r[2]; |
| $this->trace_line_offset = $r[3]; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function trigger_template_error($args = null, $line = null, $exception_class = 'SmartyCompilerException') { |
| |
| if (!isset($line)) { |
| $line = $this->lex->line; |
| } |
| $match = preg_split("/\n/", $this->lex->data); |
| $error_text = 'Syntax error in template "' . ($this->template->source->filepath) . '" on line ' . ($line + $this->trace_line_offset) . ' "' . trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1])) . '" '; |
| if (isset($args)) { |
| |
| $error_text .= $args; |
| } else { |
| |
| $error_text .= ' - Unexpected "' . $this->lex->value . '"'; |
| if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4) { |
| foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) { |
| $exp_token = $this->parser->yyTokenName[$token]; |
| if (isset($this->lex->smarty_token_names[$exp_token])) { |
| |
| $expect[] = '"' . $this->lex->smarty_token_names[$exp_token] . '"'; |
| } else { |
| |
| $expect[] = $this->parser->yyTokenName[$token]; |
| } |
| } |
| $error_text .= ', expected one of: ' . implode(' , ', $expect); |
| } |
| } |
| $e = new $exception_class($error_text); |
| $e->line = $line; |
| $e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1])); |
| $e->desc = $args; |
| $e->template = $this->template->source->filepath; |
| throw $e; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| public function trigger_expression_modifiers_error() { |
| $this->trigger_template_error( |
| 'Modifier Enforcement: All expressions must be suffixed with one of the following modifiers: ' . |
| implode(',', Smarty::$enforce_expression_modifiers), |
| null, |
| 'BrainyModifierEnforcementException' |
| ); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| public function assert_no_enforced_modifiers($static = false) { |
| if (!empty(Smarty::$enforce_expression_modifiers)) { |
| if ($static && !Smarty::$enforce_modifiers_on_static_expressions) { |
| return; |
| } |
| $this->trigger_expression_modifiers_error(); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function assert_expected_modifier($modifier_list, $static = false) { |
| if (empty(Smarty::$enforce_expression_modifiers)) { |
| return; |
| } |
| $last_modifier = end($modifier_list)[0]; |
| reset($modifier_list); |
| |
| |
| foreach ($modifier_list as $modifier) { |
| |
| if (count($modifier) === 1) { |
| continue; |
| } |
| $modifier_attributes = array_slice($modifier, 1); |
| foreach ($modifier_attributes as $attr) { |
| if (!($attr instanceof BrainyStaticWrapper)) { |
| $static = false; |
| } |
| } |
| } |
| |
| |
| if ($static && !Smarty::$enforce_modifiers_on_static_expressions) { |
| return; |
| } |
| |
| if (!in_array($last_modifier, Smarty::$enforce_expression_modifiers)) { |
| $this->trigger_expression_modifiers_error(); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| public function assert_is_not_strict($reason, $template = null) |
| { |
| if (Smarty::$strict_mode || $template && $template->isStrictMode()) { |
| $this->trigger_template_error('Strict Mode: ' . $reason, null, 'BrainyStrictModeException'); |
| } |
| } |
| |
| } |